#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>

#include <disp_manager.h>

static int fd_fb;
static struct fb_var_screeninfo g_tFBVar;	/* Current var */
static unsigned int g_dwScreenSize;
static unsigned char *g_pucFBMem; /* fb_base*/


static int FbDeviceInit(void)
{
	fd_fb = open(FB_DEVICE_NAME, O_RDWR);
	if (fd_fb < 0)
	{
		printf("can't open %s\n", FB_DEVICE_NAME);
		return -1;
	}
	if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &g_tFBVar))
	{
		printf("can't get fb's var\n");
		return -1;
	}

	g_dwScreenSize = g_tFBVar.xres * g_tFBVar.yres * g_tFBVar.bits_per_pixel / 8;
	g_pucFBMem = (unsigned char *)mmap(NULL , g_dwScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
	if (g_pucFBMem == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}

	return 0;
}

static int FbDeviceExit(void)
{
	munmap(g_pucFBMem, g_dwScreenSize);
	close(fd_fb);
	return 0;
}

int FbClear(unsigned int dwBackColor)
{
	// TODO: 还需区别不同色彩格式，参考 fb.c:FBCleanScreen
	memset(g_pucFBMem, 0xffffff, g_dwScreenSize);
	return 0;
}


/* 可以返回LCD的framebuffer, 以后上层APP可以直接操作LCD, 可以不用FbFlushRegion
 * 也可以malloc返回一块无关的buffer, 要使用FbFlushRegion
 */
static int FbGetBuffer(PT_DispBuff ptDispBuff)
{
	ptDispBuff->iXres = g_tFBVar.xres;
	ptDispBuff->iYres = g_tFBVar.yres;
	ptDispBuff->iBpp  = g_tFBVar.bits_per_pixel;
	ptDispBuff->iLineWidth = g_tFBVar.xres * g_tFBVar.bits_per_pixel / 8;;
	ptDispBuff->buff  = (unsigned char *)g_pucFBMem;
	return 0;
}

static int FbFlushRegion(PRegion ptRegion, PT_DispBuff ptDispBuff)
{
	return 0;
}

/**********************************************************************
 * 函数名称： FBShowPage
 * 功能描述： 把PT_VideoMem中的颜色数据在FrameBuffer上显示出来
 * 输入参数： ptVideoMem - 内含整屏的象素数据
 * 输出参数： 无
 * 返 回 值： 0 - 成功, 其他值 - 失败
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2013/02/08	     V1.0	  韦东山	      创建
 ***********************************************************************/
static int FbShowPage(PT_PixelDatas ptPixelDatas)
{
    if (g_pucFBMem != ptPixelDatas->aucPixelDatas)
    {
    	memcpy(g_pucFBMem, ptPixelDatas->aucPixelDatas, ptPixelDatas->iTotalBytes);
    }
	return 0;
}


static T_DispOpr g_tFramebufferOpr = {
	.name        = "fb",
	.DeviceInit  = FbDeviceInit,
	.DeviceExit  = FbDeviceExit,
	.GetBuffer   = FbGetBuffer,
	.CleanScreen = FbClear,
	.ShowPage    = FbShowPage,
	.FlushRegion = FbFlushRegion,
};


void FramebufferRegister(void)
{
	RegisterDisplay(&g_tFramebufferOpr);
}

